package us.mooresr.webtroopmanager.server.servlets;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import us.mooresr.webtroopmanager.shared.Event;
import us.mooresr.webtroopmanager.shared.EventDriver;
import us.mooresr.webtroopmanager.shared.EventParticipant;
import us.mooresr.webtroopmanager.shared.Person;
import us.mooresr.webtroopmanager.shared.Vehicle;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreInputStream;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

public class DataImportServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1374815158283699731L;
	private static final Logger log =
	      Logger.getLogger(FileUpload.class.getName());
	
	public static final Map<Long,Long> personMap = new HashMap<Long,Long>();
	public static final Map<Long,Long> vehicleMap = new HashMap<Long,Long>();
	public static final Map<Long,Long> eventMap = new HashMap<Long,Long>();
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) 
		throws ServletException, IOException {
		response.setContentType("text/plain");
		response.getOutputStream().print("<html>");
		response.getOutputStream().print("<head>");
		response.getOutputStream().print("</head>");
		response.getOutputStream().print("<body>");
		response.getOutputStream().print("<h1>This is the GET response</h1>");
		response.getOutputStream().print("</body>");
		response.getOutputStream().print("</html>");
		
	}
	
	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response) 
		throws ServletException, IOException {
		
		personMap.clear();
		vehicleMap.clear();
		eventMap.clear();

		 try {
		      ServletFileUpload upload = new ServletFileUpload();
		      response.setContentType("text/plain");
		      
		      FileItemIterator iterator = upload.getItemIterator(request);
		      
		      while (iterator.hasNext()) {
		        FileItemStream item = iterator.next();
		        InputStream stream = item.openStream();

		        if (item.isFormField()) {
		          log.warning("Got a form field: " + item.getFieldName());
		        } else {
		          log.warning("Got an uploaded file: " + item.getFieldName() +
		                      ", name = " + item.getName()); 
		          
		          // item.getFieldName indicates which file we're processing:
		          // peopleFile
		          // vehicleFile
		          // eventFile
		          // eventParticipantsFile
		          // eventDriversFile
		          // These come from the Name attribute on the FileUpload control on the form
		          
		          parseStream(stream, item.getFieldName());	    		                
		        }	
		        
		      }
		      
		      response.sendRedirect("#AdminPlace:null");
		      
		      	      
		    } catch (Exception ex) {
		      throw new ServletException(ex);
		    }
		
		
	}

	private void parseStream(InputStream stream, String filename) {
		SAXParserFactory factory = SAXParserFactory.newInstance();

		SAXParser parser;
		
		try {
			parser = factory.newSAXParser();
			if (filename.equals("peopleFile")) {
				parser.parse(stream, peopleHandler);
			} else if (filename.equals("vehicleFile")) {
				parser.parse(stream, vehicleHandler);
			} else if (filename.equals("eventFile")) {
				parser.parse(stream, eventHandler);
			} else if (filename.equals("eventParticipantFile")) {
				parser.parse(stream, participantHandler);
			} else if (filename.equals("eventDriverFile")) {
				parser.parse(stream, driverHandler);
			}
			
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	private abstract class MyHandler extends DefaultHandler {
		protected String fieldName;
		protected String fieldValue;
		
		public abstract void startDocument() throws SAXException;
		
		public void endDocument() throws SAXException {
			log.warning("End Document");
		}
		
		public void startElement(String uri, String localName, String qName, 
                Attributes attributes) throws SAXException {
			String name = attributes.getValue("name");
			log.warning("Start element " + qName);
			if (name != null) {
				log.warning("  name = '" + name + "'");
			}
			
			if (qName.equals("row")) {
				// Starting a new row
			}
			
			if (qName.equals("field")) {
				fieldName = name;
			}
			
		}
		
		public void characters(char[] ch, int start, int length) throws SAXException {
			String string = new String(ch);
			fieldValue = string.substring(start, start+length);
			log.warning("Characters: '" + fieldValue + "'");
		}
		
		public abstract void endElement(String uri, String localName, String qName) throws SAXException;
		
	}
	
	DefaultHandler peopleHandler = new MyHandler() {
		private Person person;
	
		@Override
		public void startDocument() throws SAXException {
			log.warning("Start Document");
			
			person = new Person();
			
			// Delete all people
			Objectify ofy = ObjectifyService.begin();			
			Iterable<Key<Person>> allKeys = ofy.query(Person.class).fetchKeys();
			ofy.delete(allKeys);
			
			
		}
		
		@Override
		public void endElement(String uri, String localName, String qName)
			throws SAXException {
			
			log.warning("End element " + qName);
			
			if (qName.equals("row")) {
				Objectify ofy = ObjectifyService.begin();
				Long oldId = person.getId();
				person.setId(null);
				ofy.put(person);
				Long newId = person.getId();
				DataImportServlet.personMap.put(oldId, newId);
			}
			
			if (!qName.equals("field")) {
				return;
			}
			
			// Set an object property based on fieldName and fieldValue
			if (fieldName.equals("person_id")) {
				person.setId(Long.valueOf(fieldValue));				
			}
			if (fieldName.equals("first_name")) {
				person.setFirstName(fieldValue);
				
			} 
			if (fieldName.equals("last_name")) {
				person.setLastName(fieldValue);
				
			} 
			if (fieldName.equals("type")) {
				// Old:  2 = scout, 1 = adult
				// New:  0 = scout, 1 = adult
				if (fieldValue.equals("2")) {
					person.setType(0);
				} else {
					person.setType(1);
				}	
			}
			if (fieldName.equals("med_form_a")) {
				person.setMedFormA(convertDate(fieldValue));
				
			} 
			if (fieldName.equals("med_form_b")) {
				person.setMedFormB(convertDate(fieldValue));
				
			}
			if (fieldName.equals("med_form_c")) {
				person.setMedFormC(convertDate(fieldValue));
				
			}
			if (fieldName.equals("drivers_license")) {
				person.setDriversLicense(fieldValue);
				
			}
			if (fieldName.equals("active")) {
				if (fieldValue.equals("1")) {
					person.setActive(true);
				} else {
					person.setActive(false);
				}
				
			}
			if (fieldName.equals("gender")) {
				person.setGender(fieldValue);
				
			}
			if (fieldName.equals("dob")) {
				person.setDateOfBirth(convertDate(fieldValue));
				
			}
			if (fieldName.equals("home_phone")) {
				person.setHomePhone(fieldValue);
				
			}
			if (fieldName.equals("work_phone")) {
				person.setWorkPhone(fieldValue);
				
			}
			if (fieldName.equals("cell_phone")) {
				person.setCellPhone(fieldValue);
				
			}
			if (fieldName.equals("address")) {
				person.setAddress(fieldValue);
				
			}
			if (fieldName.equals("city")) {
				person.setCity(fieldValue);
				
			}
			if (fieldName.equals("state")) {
				person.setState(fieldValue);
				
			}
			if (fieldName.equals("zip")) {
				person.setZip(fieldValue);
				
			}

		}




		
		
		
	};
	
	DefaultHandler vehicleHandler = new MyHandler() {
		private Vehicle vehicle;

		@Override
		public void startDocument() throws SAXException {
			log.warning("Start Vehicle Document");
			
			vehicle = new Vehicle();
			
			// Delete all vehicles
			Objectify ofy = ObjectifyService.begin();			
			Iterable<Key<Vehicle>> allKeys = ofy.query(Vehicle.class).fetchKeys();
			ofy.delete(allKeys);
			
			
		}
		
		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			log.warning("End element " + qName);
			
			if (qName.equals("row")) {
				Objectify ofy = ObjectifyService.begin();
				Long oldId = vehicle.getId();
				vehicle.setId(null);
				vehicle.setOwner(DataImportServlet.personMap.get(vehicle.getOwner()));
				ofy.put(vehicle);
				Long newId = vehicle.getId();
				DataImportServlet.vehicleMap.put(oldId, newId);
			}
			
			if (!qName.equals("field")) {
				return;
			}
			
			// Set an object property based on fieldName and fieldValue
			if (fieldName.equals("vehicle_id")) {
				vehicle.setId(Long.valueOf(fieldValue));
				
			}
			if (fieldName.equals("make")) {
				vehicle.setMake(fieldValue);
				
			}
			if (fieldName.equals("model")) {
				vehicle.setModel(fieldValue);
				
			}
			if (fieldName.equals("model_year")) {
				vehicle.setModelYear(Integer.valueOf(fieldValue));
				
			}
			if (fieldName.equals("seatbelts")) {
				vehicle.setSeatbelts(Integer.valueOf(fieldValue));
				
			}
			if (fieldName.equals("liability_per_person")) {
				vehicle.setLiabilityPerPerson(Integer.valueOf(fieldValue));
				
			}
			if (fieldName.equals("liability_per_accident")) {
				vehicle.setLiabilityPerAccident(Integer.valueOf(fieldValue));
				
			}
			if (fieldName.equals("property_damage")) {
				vehicle.setPropertyDamage(Integer.valueOf(fieldValue));
				
			}
			if (fieldName.equals("owner_id")) {
				vehicle.setOwner(Long.valueOf(fieldValue));
				
			}
			
		}

	
	};
	
	DefaultHandler eventHandler = new MyHandler() {
		private Event event;

		@Override
		public void startDocument() throws SAXException {
			log.warning("Start Vehicle Document");
			
			event = new Event();
			
			// Delete all events
			Objectify ofy = ObjectifyService.begin();			
			Iterable<Key<Event>> allKeys = ofy.query(Event.class).fetchKeys();
			ofy.delete(allKeys);
			
			
		}
		
		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			log.warning("End element " + qName);
			
			if (qName.equals("row")) {
				Objectify ofy = ObjectifyService.begin();
				Long oldId = event.getId();
				event.setId(null);
				event.setTourLeader(DataImportServlet.personMap.get(event.getTourLeader()));
				event.setAsstTourLeader(DataImportServlet.personMap.get(event.getAsstTourLeader()));
				ofy.put(event);
				Long newId = event.getId();
				DataImportServlet.eventMap.put(oldId, newId);
			}
			
			if (!qName.equals("field")) {
				return;
			}
			
			// Set an object property based on fieldName and fieldValue
			if (fieldName.equals("event_id")) {
				event.setId(Long.valueOf(fieldValue));			
			}
			if (fieldName.equals("event_name")) {
				event.setEventName(fieldValue);			
			}
			if (fieldName.equals("departure_location")) {
				event.setDepartureLocation(fieldValue);			
			}
			if (fieldName.equals("destination")) {
				event.setDestination(fieldValue);			
			}
			if (fieldName.equals("departure_date")) {
				event.setDepartureDate(convertDate(fieldValue));			
			}
			if (fieldName.equals("return_date")) {
				event.setReturnDate(convertDate(fieldValue));			
			}
			if (fieldName.equals("permit_filed")) {
				if (fieldValue.equals("1")) {
					event.setPermitFiled(true);
				} else {
					event.setPermitFiled(false);
				}		
			}
			if (fieldName.equals("swimming")) {
				if (fieldValue.equals("1")) {
					event.setSwimming(true);
				} else {
					event.setSwimming(false);
				}			
			}
			if (fieldName.equals("boating")) {
				if (fieldValue.equals("1")) {
					event.setBoating(true);
				} else {
					event.setBoating(false);
				}			
			}
			if (fieldName.equals("climbing")) {
				if (fieldValue.equals("1")) {
					event.setClimbing(true);
				} else {
					event.setClimbing(false);
				}			
			}
			if (fieldName.equals("flying")) {
				if (fieldValue.equals("1")) {
					event.setFlying(true);
				} else {
					event.setFlying(false);
				}			
			}
			if (fieldName.equals("high_adventure")) {
				if (fieldValue.equals("1")) {
					event.setHighAdventure(true);
				} else {
					event.setHighAdventure(false);
				}				
			}
			if (fieldName.equals("travel_miles")) {
				event.setTravelMiles(Integer.valueOf(fieldValue));			
			}
			if (fieldName.equals("tour_leader")) {
				event.setTourLeader(Long.valueOf(fieldValue));			
			}
			if (fieldName.equals("asst_tour_leader")) {
				event.setAsstTourLeader(Long.valueOf(fieldValue));			
			}
			
		}


	
		
	};
	
	DefaultHandler participantHandler = new MyHandler() {
		EventParticipant participant;
		
		@Override
		public void startDocument() throws SAXException {
			log.warning("Start Vehicle Document");
			
			participant = new EventParticipant();
			
			// Delete all event participants
			Objectify ofy = ObjectifyService.begin();			
			Iterable<Key<EventParticipant>> allKeys = ofy.query(EventParticipant.class).fetchKeys();
			ofy.delete(allKeys);
			
			
		}
		
		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			if (qName.equals("row")) {
				Objectify ofy = ObjectifyService.begin();
				participant.setId(null);
				participant.setEventId(DataImportServlet.eventMap.get(participant.getEventId()));
				participant.setPersonId(DataImportServlet.personMap.get(participant.getPersonId()));
				ofy.put(participant);

			}
			
			if (!qName.equals("field")) {
				return;
			}
			
			// Set an object property based on fieldName and fieldValue
			if (fieldName.equals("event_id")) {
				participant.setEventId(Long.valueOf(fieldValue));			
			}
			if (fieldName.equals("person_id")) {
				participant.setPersonId(Long.valueOf(fieldValue));			
			}
			if (fieldName.equals("paid")) {
				if (fieldValue.equals("1")) {
					participant.setPaid(true);
				} else {
					participant.setPaid(false);
				}		
			}
			if (fieldName.equals("permission_slip")) {
				if (fieldValue.equals("1")) {
					participant.setPermissionSlip(true);
				} else {
					participant.setPermissionSlip(false);
				}			
			}
		}


	
		
	};
	
	DefaultHandler driverHandler = new MyHandler() {
		EventDriver driver;
		
		@Override
		public void startDocument() throws SAXException {
			log.warning("Start Vehicle Document");
			
			driver = new EventDriver();
			
			// Delete all event drivers
			Objectify ofy = ObjectifyService.begin();			
			Iterable<Key<EventDriver>> allKeys = ofy.query(EventDriver.class).fetchKeys();
			ofy.delete(allKeys);
			
			
		}
		
		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			if (qName.equals("row")) {
				Objectify ofy = ObjectifyService.begin();
				driver.setId(null);
				driver.setEventId(DataImportServlet.eventMap.get(driver.getEventId()));
				driver.setPersonId(DataImportServlet.personMap.get(driver.getPersonId()));
				driver.setVehicleId(DataImportServlet.vehicleMap.get(driver.getVehicleId()));
				ofy.put(driver);

			}
			
			if (!qName.equals("field")) {
				return;
			}
			
			// Set an object property based on fieldName and fieldValue
			if (fieldName.equals("event_id")) {
				driver.setEventId(Long.valueOf(fieldValue));			
			}
			if (fieldName.equals("person_id")) {
				driver.setPersonId(Long.valueOf(fieldValue));			
			}
			if (fieldName.equals("vehicle_id")) {
				driver.setVehicleId(Long.valueOf(fieldValue));			
			}

		}

	
	};

	public Date convertDate(String fieldValue) {
		if (fieldValue.length() < 10) {
			return null;
		}
		String year = fieldValue.substring(0,4);
		String month = fieldValue.substring(5,7);
		String day = fieldValue.substring(8,10);
		String mdy = month + "/" + day + "/" + year;
		return new Date(mdy);
	}
	


}
